from fastapi import Request
from fastapi.security import HTTPBearer
from starlette.middleware.base import BaseHTTPMiddleware
from starlette.responses import Response
from jose import jwt, JWTError
import structlog
import time
import sys

from config.settings import settings

logger = structlog.get_logger()


class AuthMiddleware(BaseHTTPMiddleware):
    def __init__(self, app):
        super().__init__(app)
        self.security = HTTPBearer(auto_error=False)

        self.public_paths = {
            "/",
            "/docs",
            "/redoc",
            "/openapi.json",
            "/dashboard"
        }
        # 添加公开路径前缀匹配
        self.public_prefixes = {
            "/health"  # 匹配 /health, /health/, /health/ready 等
        }

        logger.info("🔐 AuthMiddleware 初始化完成")
        # print(f"🔐 公开路径: {self.public_paths}")
        # print(f"🔐 公开前缀: {self.public_prefixes}")

    def _is_public_path(self, path: str) -> bool:
        """检查是否为公开路径"""
        # 精确匹配
        if path in self.public_paths:
            return True

        # 前缀匹配
        for prefix in self.public_prefixes:
            if path.startswith(prefix):
                return True

        return False

    async def dispatch(self, request: Request, call_next):
        logger.info(f" AuthMiddleware检查: {request.method} {request.url.path}")
        sys.stdout.flush()

        # 检查是否为公开路径
        if self._is_public_path(request.url.path):
            sys.stdout.flush()
            return await call_next(request)

        # 检查认证头
        auth_header = request.headers.get("Authorization")
        if not auth_header:
            print(f"   ❌ 缺少Authorization头")
            sys.stdout.flush()
            logger.warning(
                "Missing authorization header",
                path=request.url.path,
                method=request.method
            )
            return Response(
                content='{"detail": "Missing authorization header"}',
                status_code=401,
                media_type="application/json"
            )

        if not auth_header.startswith("Bearer "):
            print(f"   ❌ Authorization头格式错误")
            sys.stdout.flush()
            logger.warning(
                "Invalid authorization header format",
                path=request.url.path,
                method=request.method
            )
            return Response(
                content='{"detail": "Invalid authorization header format"}',
                status_code=401,
                media_type="application/json"
            )

        # 提取并验证token
        try:
            token = auth_header.split(" ")[1]
            logger.info(f"   🔍 验证Token: {token[:20]}...")

            payload = jwt.decode(
                token,
                settings.secret_key,
                algorithms=[settings.algorithm]
            )

            # 检查过期时间
            current_time = time.time()
            exp_time = payload.get("exp")

            if exp_time and current_time > exp_time:
                print(f"   ❌ Token已过期: {exp_time} < {current_time}")
                sys.stdout.flush()
                logger.warning(
                    "Token expired",
                    path=request.url.path,
                    method=request.method,
                    exp_time=exp_time,
                    current_time=current_time
                )
                return Response(
                    content='{"detail": "Token expired"}',
                    status_code=401,
                    media_type="application/json"
                )

            # 设置用户信息
            request.state.user = payload
            user_id = payload.get("sub")
            user_email = payload.get("email")

            logger.info(f"   ✅ 认证成功: {user_id} ({user_email})")
            sys.stdout.flush()

            logger.info(
                "Authentication successful",
                user_id=user_id,
                user_email=user_email,
                path=request.url.path,
                method=request.method
            )

        except JWTError as e:
            logger.error(f"   ❌ JWT验证失败: {str(e)}")
            logger.error(f"   Token: {token[:50]}...")
            sys.stdout.flush()

            logger.warning(
                "JWT validation failed",
                error=str(e),
                path=request.url.path,
                method=request.method,
                token_preview=token[:20] + "..."
            )
            return Response(
                content='{"detail": "Invalid authentication credentials"}',
                status_code=401,
                media_type="application/json"
            )
        except Exception as e:
            print(f"   ❌ 认证过程异常: {str(e)}")
            sys.stdout.flush()

            logger.error(
                "Authentication error",
                error=str(e),
                path=request.url.path,
                method=request.method
            )
            return Response(
                content='{"detail": "Authentication error"}',
                status_code=500,
                media_type="application/json"
            )

        # 继续处理请求
        try:
            response = await call_next(request)
            return response
        except Exception as e:
            print(f"   ❌ 后续处理出错: {str(e)}")
            sys.stdout.flush()
            raise